import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingWorker.StateValue;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;

public class Application extends JFrame  implements ListSelectionListener  {

	/**  */
	private static final long serialVersionUID = -8668818312732181049L;

	private static final String INDEX_PATH = "indexDir";
	private static final String PATHS_FILE_PATH = "paths";

	private JList pathList;
	private DefaultListModel<String> listModel;

	private StandardAnalyzer analyzer;
	private Directory index;
	private TextFileIndexer indexer;

	private Action searchCancelAction;
	private Action browseAction;
	private Action removePathAction;

	private JTextField wordTextField;
	private JTextArea directoryPathTextField;
	private JTextArea messagesTextArea;
	private JProgressBar searchProgressBar;
	
	private JButton removeButton;

	private SearchForWordWorker searchWorker;

	public Application() {

		analyzer = new StandardAnalyzer(Version.LUCENE_46);
		initList();
		index = new RAMDirectory();

		initActions();
		initComponents();
		//writeDocumentsIntoTextArea();

		initIndex();
	}

	private void initList() {
		listModel = new DefaultListModel<String>();
		Vector<String> documentPaths = new Vector<String>();
		try {
			documentPaths = FileIO.readPathsFromFile(PATHS_FILE_PATH);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		for (int i = 0; i < documentPaths.size(); i++) {
			listModel.addElement(documentPaths.get(i));
		}
	}

//	private void writeDocumentsIntoTextArea() {
//		int size = documentPaths.size();
//		if (size == 0) {
//			// directoryPathTextField.setText("No Paths specified yet! \n");
//		}
////		for (int i = 0; i < size; i++) {
////			directoryPathTextField.append(documentPaths.get(i) + "\n");
////		}
//	}

	private void initIndex() {

		for (int i = 0; i < listModel.size(); i++) {
			try {
				addToIndex(listModel.get(i));
			} catch (IOException e) {

				e.printStackTrace();
			}
		}
	}

	private void addToIndex(String documentPath) throws IOException {
		try {
			indexer = new TextFileIndexer(INDEX_PATH, analyzer);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		messagesTextArea.append(indexer.indexFileOrDirectory(documentPath)
				+ "\n");
		messagesTextArea.append("Indexing all text files under: "
				+ documentPath + "\n");
		
		messagesTextArea.append("Current number of Documents: " + indexer.getCurrentNumDocs() + "\n\n");

		// ===================================================
		// after adding, we always have to call the
		// closeIndex, otherwise the index is not created
		// ===================================================

		indexer.closeIndex();
	}

	private void cancel() {
		searchWorker.cancel(true);
	}

	private void initActions() {
		browseAction = new AbstractAction("Browse") {

			private static final long serialVersionUID = 4669650683189592364L;

			@Override
			public void actionPerformed(final ActionEvent e) {
				JFileChooser fileChooser = new JFileChooser();

				/* Enabling Multiple Selection */
				fileChooser.setMultiSelectionEnabled(true);

				/* Setting Current Directory */
				fileChooser.setCurrentDirectory(new File(
						"C:\\Documents and Settings"));

				fileChooser
						.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

				fileChooser.showDialog(directoryPathTextField, "Add File");

				File selectedPfile = fileChooser.getSelectedFile();
				//directoryPathTextField.append(selectedPfile.getAbsolutePath()
					//	+ "\n");
				if(selectedPfile != null){
					String absPath = selectedPfile.getAbsolutePath();
					
					if(isUniquePath(absPath)){
						listModel.addElement(selectedPfile.getAbsolutePath());
						int index = listModel.getSize()-1;
						
						pathList.setSelectedIndex(index);
						pathList.ensureIndexIsVisible(index);
						
						//if "Remove" button is disabled
						if(!removeButton.isEnabled()) 
							removeButton.setEnabled(true);
						
						
						/** Add this File to index */
						try {
							addToIndex(selectedPfile.getAbsolutePath());
						} catch (IOException e1) {
							e1.printStackTrace();
						}	
					} else{
						System.out.println("Selected file/directory is already indexed!");
					}
				} else {
					System.out.println("File/Directory selection aborted!");
				}
						
			}

			private boolean isUniquePath(String absPath) {
				for (int i = 0; i < listModel.size(); i++) {
					if(absPath.equals(listModel.get(i))){
						return false;
					}
				}
				return true;
			}
		};

		searchCancelAction = new AbstractAction("Search") {

			private static final long serialVersionUID = 4669650683189592364L;

			@Override
			public void actionPerformed(final ActionEvent e) {
				if (searchWorker == null) {
					search();
				} else {
					cancel();
				}
			}
		};
		
		
		removePathAction = new AbstractAction("Remove") {

			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				int selectedIndex = pathList.getSelectedIndex();
				if (selectedIndex != -1) {
					String absolutPath = listModel.get(selectedIndex);
					System.out.println("File to remove: " + absolutPath);
					listModel.remove(selectedIndex);

					int size = listModel.size();

					if (size == 0) { // Nobody's left, disable "Remove".
						removeButton.setEnabled(false);

					} else { // Select an index.
						if (selectedIndex == listModel.size()) {
							// removed item in last position
							selectedIndex--;
						}

						pathList.setSelectedIndex(selectedIndex);
						pathList.ensureIndexIsVisible(selectedIndex);
						
					}

					/**
					 * remove related terms from index
					 */
					try {
						TextFileIndexer tfi = new TextFileIndexer(INDEX_PATH, analyzer);
						tfi.removeDocument(absolutPath);
						tfi.clearIndexDir();
						
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					
					//rebuild index
					initIndex();
				}
			}

		};
	}

	private void initComponents() {
		setLayout(new GridBagLayout());

		GridBagConstraints constraints = new GridBagConstraints();
		constraints.gridx = 0;
		constraints.gridy = 0;
		constraints.insets = new Insets(2, 2, 2, 2);
		add(new JLabel("Query: "), constraints);

		wordTextField = new JTextField();
		wordTextField.setText("Enter Query");
		constraints = new GridBagConstraints();
		constraints.gridx = 1;
		constraints.gridy = 0;
		constraints.gridwidth = 2;
		constraints.insets = new Insets(2, 2, 2, 2);
		constraints.weightx = 1;
		constraints.fill = GridBagConstraints.BOTH;
		add(wordTextField, constraints);
		
		
		constraints = new GridBagConstraints();
		constraints.gridx = 3;
		constraints.gridy = 0;
		constraints.insets = new Insets(2, 2, 2, 2);
		constraints.weightx = 0;
		add(new JButton(searchCancelAction), constraints);
		
		

		constraints = new GridBagConstraints();
		constraints.gridx = 0;
		constraints.gridy = 1;
		constraints.insets = new Insets(2, 2, 2, 2);
		add(new JLabel("Indexed paths: "), constraints);

		
		constraints = new GridBagConstraints();
		constraints.gridx = 0;
		constraints.gridy = 2;
		constraints.gridwidth = 1;
		constraints.insets = new Insets(2, 2, 2, 2);
		constraints.weightx = 1;
		constraints.weighty = 1;
		constraints.fill = GridBagConstraints.BOTH;
		pathList = new JList(listModel);
		//pathList.setModel();
		pathList.setSelectionMode(JList.VERTICAL_WRAP);
		pathList.addListSelectionListener(this);
		JScrollPane listScroller = new JScrollPane(pathList);
		listScroller.setPreferredSize(new Dimension(80, 80));
		add(pathList, constraints);
		

		constraints = new GridBagConstraints();
		constraints.gridx = 0;
		constraints.gridy = 3;
		constraints.weightx = 0;
		constraints.insets = new Insets(2, 2, 2, 2);
		add(new JButton(browseAction), constraints);
		
		

		messagesTextArea = new JTextArea();
		messagesTextArea.setEditable(false);
		constraints = new GridBagConstraints();
		constraints.gridx = 1;
		constraints.gridy = 2;
		constraints.gridwidth = 3;
		constraints.insets = new Insets(2, 2, 2, 2);
		constraints.weightx = 3;
		constraints.weighty = 2;
		constraints.fill = GridBagConstraints.BOTH;
		add(new JScrollPane(messagesTextArea), constraints);
		
		constraints = new GridBagConstraints();
		constraints.gridx = 0;
		constraints.gridy = 4;
		constraints.insets = new Insets(2, 2, 2, 2);
		constraints.weightx = 0;
		removeButton = new JButton();
		removeButton.setAction(removePathAction);
		removeButton.setText("Remove Path");
		if(listModel.getSize() == 0) {
			removeButton.setEnabled(false);
		}else{
			pathList.setSelectedIndex(listModel.getSize()-1);
		}
		add(removeButton, constraints);


		searchProgressBar = new JProgressBar();
		searchProgressBar.setStringPainted(true);
		searchProgressBar.setVisible(false);
		constraints = new GridBagConstraints();
		constraints.gridx = 0;
		constraints.gridy = 3;
		constraints.gridwidth = 2;
		constraints.insets = new Insets(2, 2, 2, 2);
		constraints.weightx = 1;
		constraints.fill = GridBagConstraints.BOTH;
		add(searchProgressBar, constraints);

		
	}

	private void search() {
		final String word = wordTextField.getText();

		searchWorker = new SearchForWordWorker(word, INDEX_PATH,
				messagesTextArea, analyzer, index);
		searchWorker.addPropertyChangeListener(new PropertyChangeListener() {
			@Override
			public void propertyChange(final PropertyChangeEvent event) {
				System.out.println(event);
				switch (event.getPropertyName()) {
				case "progress":
					searchProgressBar.setIndeterminate(false);
					searchProgressBar.setValue((Integer) event.getNewValue());
					break;
				case "state":
					switch ((StateValue) event.getNewValue()) {
					case DONE:
						searchProgressBar.setVisible(false);
						searchCancelAction.putValue(Action.NAME, "Search");
						searchWorker = null;
						break;
					case STARTED:
					case PENDING:
						searchCancelAction.putValue(Action.NAME, "Cancel");
						searchProgressBar.setVisible(true);
						searchProgressBar.setIndeterminate(true);
						break;
					}
					break;
				default:
				}
			}
		});
		searchWorker.execute();
	}

//	public Vector<String> getDocumentPaths() {
//		return documentPaths;
//	}

//	public void setDocumentPaths(Vector<String> documentPaths) {
//		this.documentPaths = documentPaths;
//	}

	public String getPathsFilePath() {
		return PATHS_FILE_PATH;
	}

	public void cleanUp() {
		
		/**
		 * deletes index
		 */
		try {
			TextFileIndexer tfi = new TextFileIndexer(INDEX_PATH, analyzer);
			tfi.deleteAllDocuments();
			tfi.clearIndexDir();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		
		/**
		 * saves paths in text-file
		 */
		try {
			FileIO.writePaths(PATHS_FILE_PATH, listModel);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
	
	 // This method is required by ListSelectionListener.
	  public void valueChanged(ListSelectionEvent e) {
		  System.out.println("Selection on " + pathList.getSelectedIndex());
	    if (e.getValueIsAdjusting() == false) {

	      if (pathList.getSelectedIndex() == -1) {
	        // No selection, disable fire button.
	        removeButton.setEnabled(false);

	      } else {
	        // Selection, enable the fire button.
	    	removeButton.setEnabled(true);
	      }
	    }
	  }

}
